package l2

import (
	"fmt"
	"strconv"
	"zstackgo/pkg/core/cloudbus"
	"zstackgo/pkg/core/db"
	"zstackgo/pkg/header/core"
	"zstackgo/pkg/header/message"
	hl2 "zstackgo/pkg/header/network/l2"
	"zstackgo/pkg/header/network/service"
	"zstackgo/pkg/query"
	"zstackgo/pkg/resourceconfig"
	"zstackgo/spring"

	"github.com/meilihao/golib/v2/log"
	"github.com/meilihao/golib/v2/misc"
)

func init() {
	o := new(L2VlanNetworkFactory)
	spring.Register(o, "L2VlanNetworkFactory", []*spring.PluginExtension{
		{
			Interface: "header.Component",
		},
		{
			Interface: "header.Service",
		},
		{
			Interface: "header.network.l2.L2NetworkFactory",
		},
		{
			Interface: "network.l2.L2NetworkDefaultMtu",
		},
		{
			Interface: "header.network.l2.L2NetworkGetVniExtensionPoint",
		},
	})
}

var (
	_ hl2.L2NetworkFactory              = new(L2VlanNetworkFactory)
	_ L2NetworkDefaultMtu               = new(L2VlanNetworkFactory)
	_ hl2.L2NetworkGetVniExtensionPoint = new(L2VlanNetworkFactory)
)

var (
	typVlanNetwork = hl2.NewL2NetworkType(hl2.L2_VLAN_NETWORK_TYPE, true)
)

type L2VlanNetworkFactory struct {
	dbf db.DatabaseFacade `autowire:"DatabaseFacadeImpl"`
	bus cloudbus.CloudBus `autowire:"CloudBusImpl3"`
	qf  query.MysqlQuerySubQueryExtension
	rcf resourceconfig.ResourceConfigFacade
}

func (f *L2VlanNetworkFactory) GetType() *hl2.L2NetworkType {
	return typVlanNetwork
}

func (f *L2VlanNetworkFactory) CreateL2Network(ovo *hl2.L2NetworkVO, msg *hl2.APICreateL2VlanNetworkMsg, completion core.ReturnValueCompletion[any]) {
	vo := hl2.NewL2VlanNetworkVO(ovo)
	vo.Vlan = msg.Vlan

	f.dbf.GetEntityManager().Create(vo)
	inv := hl2.L2VlanNetworkInventoryValueOf(vo)
	log.Glog.Debug(fmt.Sprintf("successfully create L2VlanNetwork, %s", misc.MarshalAnyString(inv)))

	completion.Success(inv)
}

// todo: missing vlan
func (f *L2VlanNetworkFactory) GetL2Network(vo *hl2.L2NetworkVO) hl2.L2Network {
	return NewL2VlanNetwork(vo)
}

func (f *L2VlanNetworkFactory) Start() error {
	return nil
}

func (f *L2VlanNetworkFactory) Stop() error {
	return nil
}

func (f *L2VlanNetworkFactory) HandleMessage(msg message.Message) {
	if tmp, ok := msg.(message.APIMessage); ok {
		f.HandleApiMessage(tmp)
	} else {
		f.HandleLocalMessage(msg)
	}
}

func (f *L2VlanNetworkFactory) HandleLocalMessage(msg message.Message) {
	f.bus.DealWithUnknowMessage(msg)
}

func (f *L2VlanNetworkFactory) HandleApiMessage(msg message.APIMessage) {
	f.bus.DealWithUnknowMessage(msg)
}

func (f *L2VlanNetworkFactory) GetId() string {
	return f.bus.MakeLocalServiceId(hl2.L2_VLAN_NETWORK_FACTORY_SERVICE_ID)
}

func (f *L2VlanNetworkFactory) GetL2NetworkType() string {
	return hl2.L2_VLAN_NETWORK_TYPE
}

func (f *L2VlanNetworkFactory) GetDefaultMtu(inv *hl2.L2NetworkInventory) int64 {
	tmp := f.rcf.GetResourceConfigValue(service.DHCP_MTU_VLAN, inv.Uuid)
	n, _ := strconv.ParseInt(tmp, 10, 64)
	return n
}

func (f *L2VlanNetworkFactory) GetL2NetworkVni(l2NetworkUuid string, hostUuid string) int {
	l2VlanNetworkVO := hl2.L2VlanNetworkVO{L2NetworkVO: &hl2.L2NetworkVO{}}
	f.dbf.GetEntityManager().Where("Uuid = ?", l2NetworkUuid).First(&l2VlanNetworkVO)

	return l2VlanNetworkVO.Vlan
}

func (f *L2VlanNetworkFactory) GetL2NetworkVniType() string {
	return typVlanNetwork.String()
}
